#include "file_system.h"

#ifdef WIN32
  #define POPEN _popen
  #define PCLOSE _pclose
#else
  #define POPEN popen
  #define PCLOSE pclose
#endif

void file_system::execute(const string &command, string &output) const {
  char *s = 0;

  FILE *f = POPEN(command.c_str(), "r");
  if (f == 0)
    return;

  output.resize(0);

  if (feof(f) == 0) {
    const unsigned int buffer_size = 4096;
    char buffer[buffer_size + 1] = { "\0" };
    const size_t i = fread(buffer, sizeof(char), buffer_size, f);

    if (i > 0) {
      buffer[i] = '\0';

      s = strtok(buffer, "\n");
      if (s != 0)
        output = s;
    } // if
  } // if

  PCLOSE(f);
} // file_system::execute

void file_system::execute(const string &command, vector<string> &output, size_t max /*= 64*/) const {
  output.resize(0);

  const unsigned int buffer_size = 4096;
  char buffer[buffer_size + 1] = { "\0" };
  char *s = 0;

  bool last_line_separated = false;

  FILE *f = POPEN(command.c_str(), "r");
  if (f == 0)
    return;

  while (feof(f) == 0 && max > 0) {
    const size_t i = fread(buffer, sizeof(char), buffer_size, f);

    if (i > 0) {
      buffer[i] = '\0';

      output.reserve(output.capacity() + i / 20);

      if (buffer[0] == '\n') // makes sure that chunked part will be added correctly
        last_line_separated = false;

      s = strtok(buffer, "\n");
      while (s != 0 && max > 0) {
        if (last_line_separated == true) {
          last_line_separated = false;
          (*output.rbegin()).append(s);
        } else
          output.push_back(s);

        s = strtok(0, "\n"); // next part
        --max;
      } // while

      if (s == 0 && buffer[i - 1] != 0) // makes sure that chunked part will be added correctly
          last_line_separated = true;

    } else
      break;

  } // while

  PCLOSE(f);
} // file_system::execute

bool file_system::exists(const string &file_name) const {
  FILE *f = fopen(file_name.c_str(), "rb");
  if (f != 0) {
    fclose(f);
    return true;
  } // if

  return false;
} // file_system::exists

void file_system::get_files(const string &path, vector<string> &output, size_t max /*= 64*/) const {
  #ifdef WIN32
    const string command = "dir " + path + " /a-d /b";
  #else
    const string command = "find -L " + path + " -maxdepth 1 -type f -name '*' ! -name '.*' -printf '%f\n'";
  #endif

  execute(command, output, max);
} // file_system::get_files

void file_system::get_files_including_subfolders(const string &path, vector<string> &output, size_t max /*= 64*/) const {
  #ifdef WIN32
    const string command = "dir " + path + " /a-d /b /s";
  #else
    const string command = "find -L " + path + " -type f -name '*' ! -name '.*' -printf '%f\n'";
  #endif

  execute(command, output, max);
} // file_system::get_files_including_subfolders

void file_system::get_directories(const string &path, vector<string> &output, size_t max /*= 64*/) const {
  #ifdef WIN32
    const string command = "dir " + path + " /ad /b";
  #else
    const string command = "find -L " + path + " -maxdepth 1 -type d -name '*' ! -name '.*' -printf '%f\n'";
  #endif

  execute(command, output, max);
} // file_system::get_directories

string &file_system::get_current_path(string &output) const {
  output.resize(0);

  #ifdef WIN32
    const string command = "cd"; // current path [os dependent]
  #else
    const string command = "pwd"; // current path [os dependent]
  #endif

  execute(command, output);
  return output;
} // file_system::get_current_path

string &file_system::get_username(string &output) const {
  const char *os = getenv("USERNAME");
  output.resize(0);

  if (os != 0)
    output = os;

  return output;
} // file_system::get_username

string &file_system::get_os_name(string &output) const {
  output.resize(0);

  #ifdef WIN32
    const char *os = getenv("OS");
  #else
    // OSTYPE must be exportet first
    const char *os = getenv("OSTYPE"); // getenv can only see the exportet variables
  #endif

  if (os != 0)
    output = os;

  return output;
} // file_system::get_os_name

string &file_system::get_compile_time(string &output) const {
  output = __TIME__;
  return output;
} // file_system::get_compile_time

string &file_system::get_compile_date(string &output) const {
  output = __DATE__;
  return output;
} // file_system::get_compile_date
